<template>
  <div class="el-image">
    <slot v-if="loading" name="placeholder">
      <div class="el-image__placeholder"></div>
    </slot>
    <slot v-else-if="error" name="error">
      <div class="el-image__error">图片加载失败</div>
    </slot>
    <img v-else class="el-image" v-bind="$attrs" v-on="$listeners"
      @click="clickHandler" :src="src">
    <div id="bigImage" class="imageBox" v-if="preview && showViewer" :style="{ 'z-index': zIndex }">
      <!-- 关闭按钮 -->
      <div class="actionIcon closeimg" v-show="dragbarShow" @click.stop="closeBigImage">
        <i class="V7_iconfont V7_iconV7tubiao_guanbi"></i>
      </div>
      <div id="ReplaydragbarImage" class="ReplaydragbarImage"></div>
      <imageViewer
        domId="bigImage"
        :z-index="zIndex"
        :on-close="closeViewer"
        :url-list="previewSrcList"
        :params="params" />
    </div>
  </div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
import imageViewer from '@/views/webchat/bigImg/imageViewer.vue';
const isSupportObjectFit = () => document.documentElement.style.objectFit !== undefined
// eslint-disable-next-line no-unused-vars
let imgWidth
// eslint-disable-next-line no-unused-vars
let imgHeight
window.onresize = () => {
  imgWidth = document.body.clientWidth
  imgHeight = document.body.clientHeight
}
const ObjectFit = {
  NONE: 'none',
  CONTAIN: 'contain',
  COVER: 'cover',
  FILL: 'fill',
  SCALE_DOWN: 'scale-down'
}
@Component({
  name: 'webchatBigImage',
  components: { imageViewer }
})
export default class WebchatBigImage extends Vue {
  @Prop() private previewSrcList!: []
  @Prop({ type: String }) private src!: ''
  @Prop({ type: Number, default: () => 2000 }) private zIndex

  private dragbarShow = false

  private loading = false

  private error = false

  private showViewer = false

  private show = true

  private imageWidth = 0

  private imageHeight = 0

  private params: any = {
    left: 0,
    top: 0,
    currentX: 0,
    currentY: 0,
    flag: false,
    imgWidth: 0,
    imgHeight: 0
  }

  get preview () {
    const { previewSrcList } = this
    return Array.isArray(previewSrcList) && previewSrcList.length > 0
  }

  get imageStyle () {
    const fit = this
    if (!this.$isServer && fit) {
      return isSupportObjectFit() ? { 'object-fit': fit } : this.getImageStyle(fit)
    }
    return {}
  }

  @Watch('src')
  private srcChange (val) {
    if (this.show) {
      this.loadImage()
    }
  }

  @Watch('show')
  private showChange (val) {
    if (val) {
      this.loadImage()
    }
  }

  private closeBigImage () {
    this.showViewer = false
  }

  private clickHandler () {
    this.showViewer = true
    imgWidth = document.body.clientWidth
    imgHeight = document.body.clientHeight
    this.params.imgHeight = imgHeight
    this.params.imgWidth = imgWidth
    this.$nextTick(() => {
      const oContent = document.getElementById('bigImage')
      const oBar = document.getElementById('ReplaydragbarImage')
      this.startDrag(oBar, oContent)
      this.dragBarOver()
    })
  }

  private getCss (o, key) {
    return o[key]
  }

  private startDrag (bar, target?, callback?) {
    bar.onmousedown = (event) => {
      event.preventDefault()
      if (this.getCss(target, 'offsetLeft') !== 'auto') {
        this.params.left = this.getCss(target, 'offsetLeft')
      }
      if (this.getCss(target, 'offsetTop') !== 'auto') {
        this.params.top = this.getCss(target, 'offsetTop')
      }
      this.params.flag = true
      if (!event) {
        event = window.event
        bar.onselectstart = () => {
          return false
        }
      }
      const e = event
      this.params.currentX = e.clientX
      this.params.currentY = e.clientY < 0 ? 0 : e.clientY
      this.mouseMove(target)
    }
    target.onmouseup = () => {
      this.params.flag = false
      if (this.getCss(target, 'offsetLeft') !== 'auto') {
        this.params.left = this.getCss(target, 'offsetLeft')
      }
      if (this.getCss(target, 'offsetTop') !== 'auto') {
        this.params.top = this.getCss(target, 'offsetTop')
      }
      document.onmousemove = null
    }
  }

  private mouseMove (target) {
    document.onmousemove = (event) => {
      const e: any = window.event
      const nowX = e.clientX
      const nowY = e.clientY
      let disX = 0
      let disY = 0
      if (this.params.flag) {
        this.$nextTick(() => {
          const box: any = document.getElementById('bigImage')
          const boxWidth = box.clientWidth
          disX = nowX - this.params.currentX
          disY = nowY - this.params.currentY
          // 判断上下左右的极限位置
          const currentLeft = (this.params.left) + disX < (100 - (this as any).dragWidth) ? 100 - (this as any).dragWidth : this.params.left + disX
          const limitLeft = (this.params.left) + disX > (imgWidth - boxWidth - 2) ? (imgWidth - boxWidth - 2) : currentLeft
          const limitTop = (this.params.top) + disY > (imgHeight - 34) ? (imgHeight - 34) : this.params.top + disY < 0 ? 0 : this.params.top + disY
          //  右侧靠边就停止，左侧可以无限进入
          if (limitLeft + boxWidth + 10 < document.body.clientWidth) {
            target.style.left = limitLeft + 'px'
            target.style.top = limitTop + 'px'
          }
        })
      }
    }
  }

  private dragBarOver () {
    const oContent: any = document.getElementById('bigImage')
    oContent.onmouseover = () => {
      this.dragbarShow = true
    }
    oContent.onmouseout = () => {
      this.dragbarShow = false
    }
  }

  private getImageStyle (fit) {
    const { imageWidth, imageHeight } = this
    const { clientWidth: containerWidth, clientHeight: containerHeight } = this.$el
    if (!imageWidth || !imageHeight || !containerWidth || !containerHeight) {
      return {}
    }
    const vertical = imageWidth / imageHeight < 1
    if (fit === ObjectFit.SCALE_DOWN) {
      const isSmaller = imageWidth < containerWidth && imageHeight < containerHeight
      fit = isSmaller ? ObjectFit.NONE : ObjectFit.CONTAIN
    }
    switch (fit) {
      case ObjectFit.NONE:
        return { width: 'auto', height: 'auto' }
      case ObjectFit.CONTAIN:
        return vertical ? { width: 'auto' } : { height: 'auto' }
      case ObjectFit.COVER:
        return vertical ? { height: 'auto' } : { width: 'auto' }
      default:
        return {}
    }
  }

  private loadImage () {
    if (this.$isServer) {
      return
    }
    // reset status
    this.loading = true
    this.error = false
    const img = new Image()
    img.onload = e => this.handleLoad(e, img)
    img.onerror = this.handleError.bind(this)
    // bind html attrs
    // so it can behave consistently
    Object.keys(this.$attrs).forEach((key) => {
      const value = this.$attrs[key]
      img.setAttribute(key, value)
    })
    img.src = this.src
  }

  private handleLoad (e, img) {
    this.imageWidth = img.width
    this.imageHeight = img.height
    this.loading = false
  }

  private closeViewer () {
    this.showViewer = false
  }

  private handleError (e) {
    this.loading = false
    this.error = true
    this.$emit('error', e)
  }

  private mounted () {
    this.loadImage()
  }
}
</script>
<style lang="stylus" scoped>
#bigImage
  position fixed
  top 16%
  right 16%
  bottom 16%
  left 16%
  width 68%
  height 68%
  overflow hidden
.el-image
  cursor pointer
  border 1px solid $border-main
  max-height 350px
  max-width 100%
.imageBox
  background rgba(0,0,0,0.5)
  border-radius 5px
  border-top-width: 0
  .actionIcon
    position absolute
    top 3px
    cursor pointer
    z-index 2
    background #606266
    border-radius 50%
    height 30px
    width 30px
    text-align center
    line-height 30px
    opacity 0.8
    i
      font-size 16px
  .closeimg
    right 10px
    top 10px
    color #fff
  .ReplaydragbarImage
    width 100%
    height 24px
    opacity 0
    position absolute
    cursor move
    z-index 1
</style>
